package com.geek.thread.base;

/**
 * 测试线程的八大原子操作
 * read -> 读取主内存的变量
 * load -> 将读取到主内存的变量写进线程工作内存
 * use  -> 线程执行引擎去使用load到的变量
 * assign -> 现在修改了use的变量，要assign回工作内存
 * store -> 将assign回来的变量加载到某个空间
 * write -> 将store空间里面的的变量加载回主线程
 */
public class VolatileTest {

	//不加volatile修饰
	boolean initFlag = false;

	//包装类型变量
	Integer counter = 0;
	//基本书记类型，但使用了volatile关键字修饰
//	volatile int counter = 0;

	//关闭指令重排 -Djava.compiler=NONE
//	int counter = 0;

	void start() throws Exception {
		new Thread(() -> {
			while (!initFlag){
//				counter++;
				System.out.println("running");
			}
			System.out.println("死循环结束");
		}).start();

		Thread.sleep(1000);

		new Thread(() -> {
			/**
			 * 这样子程序是停不下来的
			 * 因为线程A执行了read、load、use操作，
			 * 线程B执行了read、load、use、assign、store、write操作，
			 * 但是因为线程A没有重新read、load、use，所以线程执行引擎永远不会获取到其他线程引用到的变量
			 *
			 * 所以要当线程可以停下来，应该怎么做呢？
			 * 方法一：initFlag加个volatile关键字
			 * 方法二：加个Integer变量，然后在线程A执行write操作(基本数据类型没有这种效果，神奇)
			 * 方法三：加个int变量，然后用volatile修饰，然后在线程A执行write操作(跟方法二差不多)
			 * 方法四：关闭指令重排 -Djava.compiler=NONE
			 * 方法五，线程里面直接System.out.println("running");
			 */
			initFlag = true;
			System.out.println("将变量标志为true");
		}).start();
	}

	public static void main(String[] args) throws Exception {
		VolatileTest threadTest = new VolatileTest();
		threadTest.start();
		Thread.sleep(1000);
		System.out.println(threadTest.initFlag);
	}

}